/*
 *  Copyright 2019-2025 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package me.zhengjie.modules.bailian.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.bailian.domain.EosSystemFunctionDescription;
import me.zhengjie.modules.bailian.domain.dto.EosSystemFunctionDescriptionQueryCriteria;
import me.zhengjie.modules.bailian.mapper.EosSystemFunctionDescriptionMapper;
import me.zhengjie.modules.bailian.service.EosSystemFunctionDescriptionService;
import me.zhengjie.modules.bailian.util.AliyunBailianUtils;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageResult;
import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.RedisUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author Yaco
 * @description 服务实现
 * @date 2025-03-17
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class EosSystemFunctionDescriptionServiceImpl extends ServiceImpl<EosSystemFunctionDescriptionMapper, EosSystemFunctionDescription> implements EosSystemFunctionDescriptionService {

    private final RedisUtils redisUtils;
    private final RedissonClient redissonClient;

    private final EosSystemFunctionDescriptionMapper eosSystemFunctionDescriptionMapper;

    @Value("${app.config.bid}")
    private String businessSpaceId;

    @Value("${app.config.cid}")
    private String categoryId;

    @Value("${app.config.file_path}")
    private String filePath;

    @Value("${app.config.dashscope_api_key}")
    private String dashscopeApikey;


    @Value("${app.config.accessKey.id}")
    private String accessKeyID;

    @Value("${app.config.accessKey.secret}")
    private String accessKeySecret;

    @Value("${app.config.kbsId}")
    private String kbsIndexId;

    @Override
    public PageResult<EosSystemFunctionDescription> queryAll(EosSystemFunctionDescriptionQueryCriteria criteria, Page<Object> page) {
        return PageUtil.toPage(eosSystemFunctionDescriptionMapper.findAll(criteria, page));
    }

    @Override
    public List<EosSystemFunctionDescription> queryAll(EosSystemFunctionDescriptionQueryCriteria criteria) {
        return eosSystemFunctionDescriptionMapper.findAll(criteria);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(EosSystemFunctionDescription resources) {
        eosSystemFunctionDescriptionMapper.insert(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(EosSystemFunctionDescription resources) {
        EosSystemFunctionDescription eosSystemFunctionDescription = getById(resources.getId());
        eosSystemFunctionDescription.copy(resources);
        eosSystemFunctionDescriptionMapper.updateById(eosSystemFunctionDescription);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(List<Integer> ids) {
        eosSystemFunctionDescriptionMapper.deleteBatchIds(ids);
    }

    @Override
    public void download(List<EosSystemFunctionDescription> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (EosSystemFunctionDescription eosSystemFunctionDescription : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("业务空间ID", eosSystemFunctionDescription.getBusinessSpaceId());
            map.put("类目ID", eosSystemFunctionDescription.getCategoryId());
            map.put("处理状态", eosSystemFunctionDescription.getProcessState());
            map.put("文件类型", eosSystemFunctionDescription.getFileType());
            map.put("文件行索引", eosSystemFunctionDescription.getFileIndex());
            map.put("文档版本号", eosSystemFunctionDescription.getFileVersion());
            map.put("审核状态", eosSystemFunctionDescription.getApprovalStatus());
            map.put("审核备注", eosSystemFunctionDescription.getApprovalDesc());
            map.put("经办人", eosSystemFunctionDescription.getOperatorUserId());
            map.put("审核人", eosSystemFunctionDescription.getApprovalUserId());
            map.put("标签1", eosSystemFunctionDescription.getTag1());
            map.put("标签2", eosSystemFunctionDescription.getTag2());
            map.put("标签3", eosSystemFunctionDescription.getTag3());
            map.put("知识主题", eosSystemFunctionDescription.getKnowledgeTopic());
            map.put("知识切片(初始版)", eosSystemFunctionDescription.getKnowledgeSliceInitial());
            map.put("知识切片(最终版)", eosSystemFunctionDescription.getKnowledgeSliceFinal());
            map.put("图片", eosSystemFunctionDescription.getMetadataImage());
            map.put("响应方式", eosSystemFunctionDescription.getMetadataResponseMethod());
            map.put("槽位依赖", eosSystemFunctionDescription.getMetadataSlotDependency());
            map.put("调用工具", eosSystemFunctionDescription.getMetadataToolInvocation());
            map.put("记录创建时间", eosSystemFunctionDescription.getCreatedAt());
            map.put("记录修改时间", eosSystemFunctionDescription.getUpdatedAt());
            map.put("记录状态 (0: 不可用, 1: 可用)", eosSystemFunctionDescription.getRecordStatus());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Async
    @Override
    public void task(String structureType, EosSystemFunctionDescription resources) {
        long start = System.currentTimeMillis();
        log.info(" ### EosTask[execute] 开始执行...");
        String lockName = "EosTaskLock";

        // 1. 任务加锁,避免同时执行多个任务
        RLock lock = redissonClient.getLock(lockName);
        try {
            // 尝试获取锁，最多等待5秒，锁持有时间为60秒
            log.info(" ### EosTask[execute] 加锁[{}]开始...", lockName);
            boolean isLocked = lock.tryLock(5, 7200, TimeUnit.SECONDS);
            if (isLocked) {
                log.info(" ### EosTask[execute] 加锁[{}]成功.", lockName);

                // 结构化数据
                if ("structure".equalsIgnoreCase(structureType)) {
                    List<EosSystemFunctionDescription> descriptions = new ArrayList<>();
                    if (resources != null) {
                        descriptions.add(resources);
                    } else {
                        EosSystemFunctionDescriptionQueryCriteria criteria = new EosSystemFunctionDescriptionQueryCriteria();
                        criteria.setApprovalStatus("1");
                        // 注意:mapper中是!=, 反向条件
                        criteria.setProcessState("2");
                        criteria.setRecordStatus(1);
                        descriptions = queryAll(criteria);
                    }
                    if (CollUtil.isNotEmpty(descriptions)) {
                        for (EosSystemFunctionDescription row : descriptions) {
                            log.info(" ### EosTask[execute] 处理id=[{}], 调用大模型处理文档.", row.getId());
                            // 调用大模型处理
                            String knowledgeSliceFinal = AliyunBailianUtils.call(dashscopeApikey, row.getKnowledgeSliceInitial());
                            if (StrUtil.isBlank(knowledgeSliceFinal)) {
                                throw new Exception("id=" + row.getId() + "大模型处理失败");
                            }
                            row.setKnowledgeSliceFinal(knowledgeSliceFinal);
                            // 结构化2
                            row.setProcessState("2");
                            updateById(row);
                        }
                    } else {
                        log.info(" ### EosTask[execute] 不存在待处理数据.");
                    }
                } else {
                    unStructureData();
                }
            } else {
                log.info(" ### EosTask[execute] 加锁[{}]失败.", lockName);
            }
        } catch (Exception e) {
            log.error(" ### EosTask[execute] 业务处理失败.", e);
        } finally {
            // 确保释放锁
            lock.unlock();
            log.info(" ### EosTask[execute] 解锁[{}]成功.", lockName);
        }
        log.info(" ### EosTask[execute] 执行完毕, 耗时: {}ms", (System.currentTimeMillis() - start));
    }

    private void unStructureData() throws Exception {
        log.info(" ### EosTask[execute] 开始执行[非结构化任务]...");
        // 查询Eos表中是否存在指定数据局, 条件: process_state!= "2" && approval_status=="1"
        EosSystemFunctionDescriptionQueryCriteria criteria = new EosSystemFunctionDescriptionQueryCriteria();
        criteria.setApprovalStatus("1");
        // 注意:mapper中是!=, 反向条件
        criteria.setProcessState("2");
        criteria.setRecordStatus(1);
        List<EosSystemFunctionDescription> descriptions = queryAll(criteria);
        if (CollUtil.isNotEmpty(descriptions)) {
            log.info(" ### EosTask[execute] 存在[{}]条待处理数据.", descriptions.size());
            // 全量查询
            criteria = new EosSystemFunctionDescriptionQueryCriteria();
            criteria.setRecordStatus(1);
            descriptions = queryAll(criteria);

            // 大模型处理文档
            List<EosSystemFunctionDescription> rows = new ArrayList<>();
            for (EosSystemFunctionDescription row : descriptions) {
                log.info(" ### EosTask[execute] 处理id=[{}]", row.getId());
                // 待处理文档, 只有审核通过的才会执行处理
                if (row.getProcessState().equals("0") && row.getApprovalStatus().equals("1")) {
                    log.info(" ### EosTask[execute] 处理id=[{}], 调用大模型处理文档.", row.getId());
                    // 调用大模型处理
                    String knowledgeSliceFinal = AliyunBailianUtils.call(dashscopeApikey, row.getKnowledgeSliceInitial());
                    if (StrUtil.isBlank(knowledgeSliceFinal)) {
                        throw new Exception("id=" + row.getId() + "大模型处理失败");
                    }
                    row.setKnowledgeSliceFinal(knowledgeSliceFinal);
                    // 非结构化1 结构化2
                    row.setProcessState("1");
//                            row.setProcessState("2");
                    updateById(row);
                }
                rows.add(row);
            }
            // 写入excel文档
            String fileName = "EOS系统功能说明_" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + ".xlsx";
            String fullPath = filePath + fileName;
            boolean writeExcelFlag = AliyunBailianUtils.writeExcel(fullPath, rows);
            // 写入成功
            if (writeExcelFlag) {
                // 同步阿里云百炼知识库
                boolean syncFlag = AliyunBailianUtils.syncBailianKbs(accessKeyID, accessKeySecret, categoryId, businessSpaceId, kbsIndexId, fullPath);
                if (syncFlag) {
                    // 修改处理状态
                    UpdateWrapper<EosSystemFunctionDescription> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.set("process_state", "2");
                    updateWrapper.eq("record_status", 1);
                    boolean updateFlag = update(updateWrapper);
                    if (updateFlag) {
                        log.info(" ### EosTask[execute] 最终修改process_state=2 [成功].");
                    } else {
                        log.info(" ### EosTask[execute] 最终修改process_state=2 [失败].");
                    }

                } else {
                    log.info(" ### EosTask[execute] 同步知识库失败.");
                }
            } else {
                log.info(" ### EosTask[execute] 写入文件失败.");
            }
        } else {
            log.info(" ### EosTask[execute] 不存在待处理数据.");
        }

    }


}
